package cmd

import (
	"io/ioutil"
	"strings"

	log "github.com/sirupsen/logrus"

	"gitee.com/minph/siphan/core"
	"gitee.com/minph/siphan/fs"
	"github.com/urfave/cli/v2"
)

func DecodeHandler(c *cli.Context) error {
	key := c.String("key")
	file := c.String("file")
	output := c.String("output")

	codeSlice, err := fs.ReadHexKeyFromFile(key)
	if err != nil {
		log.Errorf("Can not read data of [%v]\n", key)
		return wrap(err)
	}

	content, err := ioutil.ReadFile(file)
	if err != nil {
		log.Errorf("Can not read data of [%v]\n", file)
		return wrap(err)
	}

	return decodeFromContent(string(content), codeSlice, output)

}

func decodeFromContent(content string, codeSlice core.CodeSlice, outputName string) error {

	parsedContent, err := codeSlice.ParseHexDataList(strings.Split(string(content), " "))
	if err != nil {
		return wrap(err)
	}

	val, err := core.Decrypt(parsedContent, codeSlice.GenStr())
	if err != nil {
		return wrap(err)
	}

	err = fs.ClearFile(outputName)
	if err != nil {
		return wrap(err)
	}

	return writeDecodeData(outputName, val)
}

func escapeStr(data string) string {
	data = strings.ReplaceAll(data, "\\a", "\a")
	data = strings.ReplaceAll(data, "\\b", "\b")
	data = strings.ReplaceAll(data, "\\f", "\f")
	data = strings.ReplaceAll(data, "\\n", "\n")
	data = strings.ReplaceAll(data, "\\r", "\r")
	data = strings.ReplaceAll(data, "\\t", "\t")
	data = strings.ReplaceAll(data, `\"`, `"`)
	data = strings.ReplaceAll(data, `\?`, `?`)
	data = strings.ReplaceAll(data, `\*`, `*`)
	data = strings.ReplaceAll(data, `\$`, `$`)
	data = strings.ReplaceAll(data, `\+`, `+`)
	data = strings.ReplaceAll(data, `\.`, `.`)
	data = strings.ReplaceAll(data, `\"`, `"`)
	data = strings.ReplaceAll(data, `\\`, `\`)
	return data
}

func writeDecodeData(outputName, data string) error {
	// 处理换行符
	outputContent := escapeStr(data)

	err := fs.WriteNewFile(outputName, outputContent)
	if err != nil {
		log.Errorf("Can not write decrypt data into [%v]\n", outputName)
		return wrap(err)
	}

	log.Info("decrypt file successfully")
	log.Infof("see decrypt file at [%v]\n", outputName)
	return nil
}
